package com.uinnova.product.eam.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.binary.json.JSONException;
import com.uinnova.product.eam.model.dto.DiagramSnapshotVO;
import com.uinnova.product.eam.service.DiagramMainSvc;
import com.uinnova.product.eam.service.DiagramSnapshotSvc;
import com.uinnova.product.vmdb.comm.i18n.MessageUtil;
import com.uinnova.product.vmdb.comm.util.CommUtil;
import com.uinnova.project.base.diagram.comm.diagram.*;
import com.uinnova.project.base.diagram.comm.model.*;
import com.uinnova.project.db.diagram.VcDiagramVersionDao;
import com.uinnova.project.db.eam.*;
import com.uinnova.project.model.diagram.event.DiagramRuleEnum;
import com.uinnova.project.model.diagram.event.RuleParams;
import com.uinnova.project.service.eam.ESDiagramSvc;
import com.uinnova.project.service.eam.ESDiagramVersionSvc;
import com.uinnova.project.service.eam.impl.ESDiagramSvcImpl;
import com.uinnova.project.service.event.IHiddenService;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.cmdb.ESCIClassSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.sys.microservice.IResourceSvc;
import com.uino.util.rsm.RsmUtils;
import com.uino.util.sys.SysUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Service
public class DiagramMainSvcImpl implements DiagramMainSvc {

    @Autowired
    ESDiagramSvc esDiagramSvc;
    @Autowired
    VcDiagramVersionDao diagramVersionDao;
    @Autowired
    ESDiagramSheetDao esDiagramSheetDao;
    @Autowired
    IUserApiSvc userApiSvc;
    @Autowired
    ESDiagramVersionSvc esDiagramVersionSvc;
    @Autowired
    IHiddenService hiddenService;
    @Autowired
    ESDiagramNodeDao esDiagramNodeDao;
    @Autowired
    ESDiagramLinkDao esDiagramLinkDao;
    @Autowired
    ESDiagramDao esDiagramDao;
    @Autowired
    ESShareLinkDao shareLinkDao;
    @Autowired
    RsmUtils rsmUtils;
    @Autowired(required = false)
    IResourceSvc resourceSvc;
    @Autowired
    ESCIClassSvc esciClassSvc;
    @Autowired
    DiagramSnapshotSvc diagramSnapshotSvc;

    @Value("${http.resource.space}")
    private String httpResourceUrl;
    @Value("${local.resource.space}")
    private String localPath;

    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
    private static final Long SYS_DOMAIN_ID = 1L;
    private static final Logger logger = LoggerFactory.getLogger(ESDiagramSvcImpl.class);
    public static ExecutorService executor = Executors.newFixedThreadPool(10);
    private final static String DIAGRAM_OPTYPE = "DIAGRAM";
    private final static String SHEET_OPTYPE = "SHEET";
    private final static String SHEET_COPY_OPTYPE = "SHEET_COPY";
    private final static String NODE_OPTYPE = "NODE";
    private final static String LINK_OPTYPE = "LINK";
    private final static String ADD_OPTYPE = "ADD";
    private final static String DELETE_OPTYPE = "DELETE";
    private final static String UPDATE_OPTYPE = "UPDATE";
    private final static long MAX_QUERY_COUNT = 30000;
    private final static long PAGE_COUNT = 3000;

    @Override
    public Map<String, List<ESResponseStruct>> saveOrUpdateDiagramComponent(String jsonStr) {
        JSONObject jsonObj = JSON.parseObject(jsonStr);
//        Long diagramId = jsonObj.getLong("diagramId");
        String encryptDiagramId = jsonObj.getString("diagramId");
        if (StringUtils.isEmpty(encryptDiagramId)) {
            throw new BinaryException("传参错误，视图id不能为空");
        }
        Long[] ids = esDiagramSvc.queryDiagramInfoBydEnergy(new String[]{encryptDiagramId});
        Long diagramId = ids[0];
        MessageUtil.checkEmpty(diagramId, "diagramId");
        ESDiagram esDiagram = esDiagramSvc.judgeSingleDiagramAuth(diagramId, "", true);
        Long modifyTime = esDiagram.getModifyTime();
        Long currTime = BinaryUtils.getNumberDateTime();
        //更新前需要判断是否要新建历史版本，查出信息，异步保存
        boolean isCreateVersion = false;
        VcDiagramVersion currDiagramVersion = diagramVersionDao.selectById(diagramId);
        if (currDiagramVersion != null) {
            String versionName = currDiagramVersion.getVersionName();
            /*
                创建历史版本的条件判断
                    首先判断版本名称是否为空，
                        不为空，创建
                        为空，判断距离视图上一次修改时间是否超过三分钟
                            超过，创建
            */
            if (!BinaryUtils.isEmpty(versionName)) {
                isCreateVersion = true;
            }
        }
        if (!isCreateVersion) {
            if ((currTime - modifyTime) > 300) {
                isCreateVersion = true;
            }
        }
        if (isCreateVersion) {
            //满足创建版本条件，创建当前视图的历史版本
            //1.查出视图信息，包含基础信息和组件
            ESDiagramSheetQuery sheetQuery = new ESDiagramSheetQuery();
            sheetQuery.setDiagramId(diagramId);
            List<ESDiagramSheetDTO> sheetList = esDiagramSheetDao.getListByCdt(sheetQuery);
            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
            nodeQuery.setDiagramId(diagramId);
            List<ESDiagramNode> nodeList = new ArrayList<>();
            nodeList = getAllNode(nodeQuery, nodeList);
            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
            linkQuery.setDiagramId(diagramId);
            List<ESDiagramLink> linkList = new ArrayList<>();
            linkList = getAllLink(linkQuery, linkList);
            //2.获取上一次操作用户和本次操作用户的信息，然后保存历史版本
            ESSimpleDiagram esSimpleDiagram = new ESSimpleDiagram(esDiagram, sheetList, nodeList, linkList);
            SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
            String currLoginCode = currentUserInfo.getLoginCode();
            String lastModifierCode = esDiagram.getModifier();
            SysUser tmpModifier = new SysUser();
            SysUser currUser = new SysUser();
            boolean objFlag = true;
            //当前用户不是上一次操作用户，需要手动查询上一次操作用户信息
            CSysUser userQuery = new CSysUser();
            if (!lastModifierCode.equals(currLoginCode)) {
                userQuery.setLoginCodes(new String[]{currLoginCode, lastModifierCode});
            } else {
                userQuery.setLoginCodes(new String[]{currLoginCode});
            }
            userQuery.setDomainId(SYS_DOMAIN_ID);
            userQuery.setSuperUserFlags(new Integer[]{0, 1});
            List<SysUser> sysUsers = userApiSvc.getSysUserByCdt(userQuery);
            if (!BinaryUtils.isEmpty(sysUsers)) {
                for (SysUser sysUser : sysUsers) {
                    String loginCode = sysUser.getLoginCode();
                    if (loginCode.equals(currLoginCode)) {
                        currUser = sysUser;
                        continue;
                    }
                    if (loginCode.equals(lastModifierCode)) {
                        tmpModifier = sysUser;
                        objFlag = false;
                    }
                }
            } else {
                logger.error("用户信息为空，新增历史版本失败");
            }
            if (objFlag) {
                //logger.info("上次修改用户已被删除，取当前用户作为上次修改用户");
                tmpModifier = currUser;
            }
            SysUser lastModifier = tmpModifier;
            SysUser finalCurrUser = currUser;
            executor.submit(() ->
                    {

                        try {
                            DiagramSnapshotVO snapshotVO = new DiagramSnapshotVO();
                            snapshotVO.setMainDiagramId(encryptDiagramId);
                            diagramSnapshotSvc.generateSnapshotByDiagramIds(Collections.singletonList(snapshotVO), currentUserInfo, Boolean.TRUE);
                            logger.info("保存历史版本成功,并成功关联数据");
                        } catch (Exception manual) {
                            logger.info("保存历史版本失败，失败的diagramId：{}, 报错信息：{}", esSimpleDiagram.getEsDiagram().getId(), manual.getMessage());
                            /*try {
                                //因为不同线程之间token不共享，而保存历史版本时需要用户信息，所以需要手动传递
                                esDiagramVersionSvc.saveESDiagramVersion(esSimpleDiagram, finalCurrUser, lastModifier);
                                logger.info("保存历史版本成功，未关联数据");
                            } catch (Exception auto) {
                                auto.printStackTrace();

                            }*/
                        }


                    }
            );
        }
        //diagram包含的sheet、link、node更新时，需要更新diagram的modifyTime
        Map<String, List<ESResponseStruct>> resultMap = new HashMap<>();
        boolean change = false;
        if (jsonStr.contains(ADD_OPTYPE)) {
            JSONArray addArr = new JSONArray();
            try {
                addArr = jsonObj.getJSONArray(ADD_OPTYPE);
            } catch (JSONException jsonException) {
                logger.info("关键字特殊处理");
            }
            if (!BinaryUtils.isEmpty(addArr)) {
                for (int i = 0; i < addArr.size(); ++i) {
                    JSONObject tempJson = addArr.getJSONObject(i);
                    //1.获取操作类型和修改数据，并进行判空处理
                    String opType = tempJson.getString("opType");
                    String opList = tempJson.getString("opList");
                    if (BinaryUtils.isEmpty(opList) || BinaryUtils.isEmpty(opType)) {
                        throw new BinaryException("操作类型或者待更新数据不能为空");
                    }
                    switch (opType) {
                        case SHEET_OPTYPE: {
                            change = change || true;
                            //新增sheet
                            List<ESResponseStruct> structList = saveOrUpdateSheet(diagramId, opList, false);
                            resultMap.put(SHEET_OPTYPE, structList);
                            break;
                        }
                        case NODE_OPTYPE: {
                            change = change || true;
                            //新增node
                            String sheetId = tempJson.getString("sheetId");
                            List<ESResponseStruct> structList = extendSaveOrUpdateNode(diagramId, sheetId, opList, false);
                            resultMap.put(NODE_OPTYPE, structList);
                            break;
                        }
                        case LINK_OPTYPE: {
                            change = change || true;
                            //新增link
                            String sheetId = tempJson.getString("sheetId");
                            String attachCiCode = tempJson.getString("attachCiCode")==null ? "":tempJson.getString("attachCiCode");
                            List<ESResponseStruct> structList = extendSaveOrUpdateLink(diagramId, sheetId, opList, false);
                            resultMap.put(LINK_OPTYPE, structList);
                            if (!BinaryUtils.isEmpty(attachCiCode) && esDiagram.getDirType()==100 && !BinaryUtils.isEmpty(esDiagram.getDiagramSubType()) && esDiagram.getDiagramSubType() == 4) {
                                try {
                                    RuleParams params = new RuleParams();
                                    params.setCiCode(attachCiCode);
                                    params.setDiagramId(esDiagram.getId());
                                    params.setDomainId(esDiagram.getDomainId());
                                    params.setOwnerCode(esDiagram.getOwnerCode());
                                    params.setSheetId(sheetId);
                                    params.setRuleType(DiagramRuleEnum.TASK_DIAGRAM);
                                    hiddenService.process(params);
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                }
                            }
                            break;
                        }
                        case SHEET_COPY_OPTYPE:
                            change = change || true;
                            List<ESDiagramSheetDTO> copySheetList = JSONUtil.toList(opList, ESDiagramSheetDTO.class);
                            List<ESDiagramNode> copyNodeList = new ArrayList<>();
                            List<ESDiagramLink> copyLinkList = new ArrayList<>();
                            for (ESDiagramSheetDTO sheetDTO : copySheetList) {
                                //1.获取新老sheetId
                                String oldSheetId = sheetDTO.getCopyId();
                                String newSheetId = sheetDTO.getSheetId();
                                sheetDTO.setDiagramId(diagramId);
                                //2.查询sheet包含的所有node节点并复制
                                ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
                                nodeQuery.setDiagramId(diagramId);
                                nodeQuery.setSheetIdEqual(oldSheetId);
                                BoolQueryBuilder nodeBool = ESUtil.cdtToBuilder(nodeQuery);
                                List<ESDiagramNode> nodeList = esDiagramNodeDao.getListByQuery(nodeBool);
                                if (!BinaryUtils.isEmpty(nodeList)) {
                                    for (ESDiagramNode esDiagramNode : nodeList) {
                                        esDiagramNode.setId(null);
                                        esDiagramNode.setSheetId(newSheetId);
                                    }
                                    copyNodeList.addAll(nodeList);
                                }
                                //3.查询sheet包含的所有link节点并复制
                                ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
                                linkQuery.setDiagramId(diagramId);
                                linkQuery.setSheetIdEqual(oldSheetId);
                                BoolQueryBuilder linkBool = ESUtil.cdtToBuilder(linkQuery);
                                List<ESDiagramLink> linkList = esDiagramLinkDao.getListByQuery(linkBool);
                                if (!BinaryUtils.isEmpty(linkList)) {
                                    for (ESDiagramLink esDiagramLink : linkList) {
                                        esDiagramLink.setId(null);
                                        esDiagramLink.setSheetId(newSheetId);
                                    }
                                    copyLinkList.addAll(linkList);
                                }
                            }
                            esDiagramSheetDao.saveOrUpdateBatch(copySheetList);
                            esDiagramNodeDao.saveOrUpdateBatch(copyNodeList);
                            esDiagramLinkDao.saveOrUpdateBatch(copyLinkList);
                            break;
                        default:
                            change = change || false;
                            logger.info("操作类型不符合规范");
                            break;
                    }
                }
            }
        }
        if (jsonStr.contains(UPDATE_OPTYPE)) {
            JSONArray updateArr = new JSONArray();
            try {
                updateArr = jsonObj.getJSONArray(UPDATE_OPTYPE);
            } catch (JSONException jsonException) {
                logger.info("关键字特殊处理");
            }
            if (!BinaryUtils.isEmpty(updateArr)) {
                for (int i = 0; i < updateArr.size(); ++i) {
                    JSONObject tempJson = updateArr.getJSONObject(i);
                    //1.获取操作类型和修改数据，并进行判空处理
                    String opType = tempJson.getString("opType");
                    String opList = tempJson.getString("opList");
                    if (BinaryUtils.isEmpty(opList) || BinaryUtils.isEmpty(opType)) {
                        throw new BinaryException("操作类型或者待更新数据不能为空");
                    }
                    change = change || true;
                    switch (opType) {
                        case DIAGRAM_OPTYPE:
                            //diagram更新
                            List<ESDiagramTemp> esDiagramList = JSONUtil.toList(opList, ESDiagramTemp.class);
                            //获取下创建时间回填，否则会更新创建时间(见AbstractESBaseDao.fillPreferencesInfo方法)
                            List<String> updateDiagramIds = esDiagramList.stream().map(ESDiagramTemp::getId).collect(Collectors.toList());
                            List<ESDiagram> oldDiagrams = esDiagramSvc.queryDBDiagramInfoByIds(updateDiagramIds.toArray(new String[updateDiagramIds.size()]));
                            Map<String, ESDiagram> oldDiagramMap = oldDiagrams.stream().collect(Collectors.toMap(ESDiagram::getDEnergy, e -> e, (k1,k2) -> k1));
                            List<ESDiagram> esList = new ArrayList<>();
                            for (ESDiagramTemp tmpDiagram : esDiagramList) {
                                String id = tmpDiagram.getId();
                                if (oldDiagramMap.containsKey(id)) {
                                    tmpDiagram.setCreateTime(oldDiagramMap.get(id).getCreateTime());
                                }
                                tmpDiagram.setId(null);
                                String iconPath = tmpDiagram.getIcon1();
                                if (!StringUtils.isEmpty(iconPath)) {
                                    iconPath = iconPath.replaceFirst(httpResourceUrl, "");
                                    tmpDiagram.setIcon1(iconPath);
                                }
                                ESDiagram diagram = CommUtil.copy(tmpDiagram, ESDiagram.class);
                                diagram.setId(esDiagramSvc.queryDiagramInfoByEnergy(id));
                                esList.add(diagram);
                            }
                            esDiagramDao.saveOrUpdateBatchWithOption(esList);
                            break;
                        case SHEET_OPTYPE:
                            //更新sheet
                            saveOrUpdateSheet(diagramId, opList, true);
                            break;
                        case NODE_OPTYPE: {
                            //更新node
                            String sheetId = tempJson.getString("sheetId");
                            extendSaveOrUpdateNode(diagramId, sheetId, opList, true);
                            break;
                        }
                        case LINK_OPTYPE: {
                            //更新link
                            String sheetId = tempJson.getString("sheetId");
                            extendSaveOrUpdateLink(diagramId, sheetId, opList, true);
                            break;
                        }
                    }
                }
            }
        }
        if (jsonStr.contains(DELETE_OPTYPE)) {
            JSONArray deleteArr = new JSONArray();
            try {
                deleteArr = jsonObj.getJSONArray(DELETE_OPTYPE);
            } catch (JSONException jsonException) {
                logger.info("关键字特殊处理");
            }
            if (!BinaryUtils.isEmpty(deleteArr)) {
                for (int i = 0; i < deleteArr.size(); ++i) {
                    JSONObject tempJson = deleteArr.getJSONObject(i);
                    //1.获取操作类型和修改数据，并进行判空处理
                    String opType = tempJson.getString("opType");
                    JSONArray opArr = tempJson.getJSONArray("opList");
                    if (BinaryUtils.isEmpty(opArr) || BinaryUtils.isEmpty(opType)) {
                        throw new BinaryException("操作类型或者待更新数据不能为空");
                    }
                    List<String> deleteIdList = new ArrayList<>();
                    for (int tmp = 0; tmp < opArr.size(); ++tmp) {
                        deleteIdList.add(opArr.getString(tmp));
                    }
                    //移除空值
                    deleteIdList.removeIf(Objects::isNull);
                    String[] deleteIdArr;
                    if (!BinaryUtils.isEmpty(deleteIdList)) {
                        deleteIdArr = deleteIdList.toArray(new String[0]);
                    } else {
                        throw new BinaryException("待删除id列表不能为空");
                    }
                    change = change || true;
                    switch (opType) {
                        case SHEET_OPTYPE: {
                            //1.删除sheet
                            ESDiagramSheetQuery sheetQuery = new ESDiagramSheetQuery();
                            sheetQuery.setDiagramId(diagramId);
                            sheetQuery.setSheetIds(deleteIdArr);
                            if (sheetQuery.getSheetIds().length > 0) {
                                esDiagramSheetDao.deleteByQuery(ESUtil.cdtToBuilder(sheetQuery), true);
                            }

                            //2.删除sheet包含的所有node节点
                            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
                            nodeQuery.setDiagramId(diagramId);
                            nodeQuery.setSheetIds(deleteIdArr);
                            if (nodeQuery.getSheetIds().length > 0) {
                                esDiagramNodeDao.deleteByQuery(ESUtil.cdtToBuilder(nodeQuery), true);
                            }
                            //3.删除sheet包含的所有link节点
                            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
                            linkQuery.setDiagramId(diagramId);
                            linkQuery.setSheetIds(deleteIdArr);
                            if (linkQuery.getSheetIds().length > 0) {
                                esDiagramLinkDao.deleteByQuery(ESUtil.cdtToBuilder(linkQuery), true);
                            }
                            //4.异步删除该sheet对应的所有图片
                            executor.submit(() ->
                                    {
                                        try {
                                            //删除历史记录
                                            DiagramShareLinkQuery shareLinkQuery = new DiagramShareLinkQuery();
                                            shareLinkQuery.setSheetIds(deleteIdArr);
                                            shareLinkQuery.setLinkType(0);
                                            List<DiagramShareLink> deleteLinkList = shareLinkDao.getListByCdt(shareLinkQuery);
                                            if (!BinaryUtils.isEmpty(deleteLinkList)) {
                                                //删除链接
                                                Set<Long> linkIdSet = deleteLinkList
                                                        .stream()
                                                        .map(DiagramShareLink::getId)
                                                        .collect(Collectors.toSet());
                                                shareLinkDao.deleteByIds(linkIdSet);
                                                //删除文件
                                                for (DiagramShareLink shareLink : deleteLinkList) {
                                                    if (!BinaryUtils.isEmpty(shareLink)) {
                                                        String fileUrl = shareLink.getStorePath();
                                                        if (!BinaryUtils.isEmpty(fileUrl)) {
                                                            localPath = localPath.replace("/", FILE_SEPARATOR).replace("\\", FILE_SEPARATOR);
                                                            fileUrl = fileUrl.startsWith(localPath) ? fileUrl : localPath + fileUrl;
                                                            File delFile = new File(fileUrl);
                                                            if (delFile.exists()) {
                                                                delFile.delete();
                                                                rsmUtils.deleteRsm(fileUrl);
                                                                resourceSvc.saveSyncResourceInfo(fileUrl, httpResourceUrl + fileUrl, false, 1);
                                                                logger.info("文件删除成功");
                                                            }
                                                        } else {
                                                            logger.info("fileUrl为空，无法删除服务器中文件，ids={}", shareLink.getId());
                                                        }
                                                    }
                                                }
                                            }
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                            logger.info("删除分享链接失败，视图id={}, sheetId={}", diagramId, deleteIdArr);
                                        }
                                    }
                            );
                            break;
                        }
                        case NODE_OPTYPE: {
                            String sheetId = tempJson.getString("sheetId");
                            if (StringUtils.isEmpty(sheetId)) {
                                throw new BinaryException("sheetId不能为空");
                            }
                            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
                            nodeQuery.setDiagramId(diagramId);
                            nodeQuery.setSheetIdEqual(sheetId);
                            nodeQuery.setKeys(deleteIdArr);
                            if (nodeQuery.getSheetIdEqual() != null && nodeQuery.getKeys().length > 0) {
                                esDiagramNodeDao.deleteByQuery(ESUtil.cdtToBuilder(nodeQuery), true);
                            }
                            break;
                        }
                        case LINK_OPTYPE: {
                            String sheetId = tempJson.getString("sheetId");
                            String attachCiCode = tempJson.getString("attachCiCode")==null?"":tempJson.getString("attachCiCode");
                            if (StringUtils.isEmpty(sheetId)) {
                                throw new BinaryException("sheetId不能为空");
                            }
                            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
                            linkQuery.setDiagramId(diagramId);
                            linkQuery.setSheetIdEqual(sheetId);
                            linkQuery.setKeys(deleteIdArr);
                            if (linkQuery.getSheetIdEqual() != null && linkQuery.getKeys().length > 0) {
                                esDiagramLinkDao.deleteByQuery(ESUtil.cdtToBuilder(linkQuery), true);
                                if (!BinaryUtils.isEmpty(attachCiCode) && !BinaryUtils.isEmpty(esDiagram.getDiagramSubType()) && esDiagram.getDiagramSubType() == 4) {
                                    try {
                                        RuleParams params = new RuleParams();
                                        params.setCiCode(attachCiCode);
                                        params.setDiagramId(diagramId);
                                        params.setDomainId(esDiagram.getDomainId());
                                        params.setOwnerCode(esDiagram.getOwnerCode());
                                        params.setSheetId(sheetId);
                                        params.setExpectKeys(Arrays.asList(deleteIdArr));
                                        params.setRuleType(DiagramRuleEnum.TASK_DIAGRAM);
                                        hiddenService.process(params);
                                    } catch (Exception e) {
                                        logger.error(e.getMessage(), e);
                                    }
                                }
                            }
                            break;
                        }
                        default:
                            throw new BinaryException("不合法的操作类型");
                    }
                }
            }
        }
        //更新diagram的modifyTime，公共组件会自动调用
        if (!BinaryUtils.isEmpty(diagramId)) {
            synchronized (this) {
                if (change) {
                    esDiagramDao.increaseVersionAndTime(diagramId);
                } else {
                    esDiagramDao.updateModifyTime(diagramId);
                }
            }
        }
        return resultMap;
    }


    public List<ESDiagramNode> getAllNode(ESDiagramNodeQueryBean nodeQuery, List<ESDiagramNode> nodeList) {
        long totalNodeCount = esDiagramNodeDao.countByCondition(ESUtil.cdtToBuilder(nodeQuery));
        if (totalNodeCount > MAX_QUERY_COUNT) {
            throw new BinaryException("一次查询数据不能超过30000条");
        }
        if (totalNodeCount > PAGE_COUNT) {
            long loopCount = totalNodeCount / PAGE_COUNT + 1;
            for (int start = 1; start <= loopCount; ++start) {
                //分页查询
                Page<ESDiagramNode> tmpList = esDiagramNodeDao.getListByCdt(start, 3000, nodeQuery);
                nodeList.addAll(tmpList.getData());
            }
        } else {
            nodeList = esDiagramNodeDao.getListByCdt(nodeQuery);
        }
        List<ESCIClassInfo> listByQueryScroll = esciClassSvc.getListByQueryScroll(QueryBuilders.matchAllQuery());
        Map<String, Long> convertMap = listByQueryScroll.stream().collect(Collectors.toMap(ESCIClassInfo::getClassName, ESCIClassInfo::getId, (k1, k2) -> k1));

        nodeList.forEach(n -> {
            String nodeJson = n.getNodeJson();
            JSONObject jsonObject = JSON.parseObject(nodeJson);
            String className = jsonObject.getString("className");
            Long classId = jsonObject.getLong("classId");
            if (!BinaryUtils.isEmpty(classId) && org.apache.commons.lang3.StringUtils.isNotEmpty(className)) {
                Long aLong = convertMap.get(className);
                if (aLong != null && !classId.equals(aLong)) {
                    jsonObject.put("classId", aLong);
                    n.setNodeJson(JSON.toJSONString(jsonObject));
                }
            }
        });
        return nodeList;
    }

    public List<ESDiagramLink> getAllLink(ESDiagramLinkQueryBean linkQuery, List<ESDiagramLink> linkList) {
        long totalLinkCount = esDiagramLinkDao.countByCondition(ESUtil.cdtToBuilder(linkQuery));
        if (totalLinkCount > MAX_QUERY_COUNT) {
            throw new BinaryException("一次查询数据不能超过30000条");
        }
        if (totalLinkCount > PAGE_COUNT) {
            long loopCount = totalLinkCount / PAGE_COUNT + 1;
            for (int start = 1; start <= loopCount; ++start) {
                //分页查询
                Page<ESDiagramLink> tmpList = esDiagramLinkDao.getListByCdt(start, 3000, linkQuery);
                linkList.addAll(tmpList.getData());
            }
        } else {
            linkList = esDiagramLinkDao.getListByCdt(linkQuery);
        }
        return linkList;
    }

    /**
     * 前端想要实现的是拉一个sheet，没有id，有sheetId（即前端自己生成的sheet标识）
     * 这样就不用等待后台返回id，就能对sheet进行各种操作
     * 前台只传递sheetId，不传递id
     * 实现思路：
     * 对于新增操作，无需干预，会自动新增
     * 对于更新操作，先根据sheetId查出对于的obj，
     * 如果有，就将obj的id设为updateSheet的id
     * 如果没有，就还是一个新增操作
     */
    private List<ESResponseStruct> saveOrUpdateSheet(Long diagramId, String opList, Boolean flag) {
        MessageUtil.checkEmpty(diagramId, "保存或更新link时diagramId不能为空");
        List<ESDiagramSheetDTO> saveOrUpdateSheetList = JSONUtil.toList(opList, ESDiagramSheetDTO.class);
        List<ESResponseStruct> structList = new ArrayList<>();
        ESResponseStruct esResponseStruct = new ESResponseStruct();
        //更新操作
        if (flag) {
            //获取所有的sheetId，并根据sheetId查出其对应的sheet对象
            String[] sheetIdArr = saveOrUpdateSheetList
                    .stream()
                    .map(ESDiagramSheetDTO::getSheetId)
                    .distinct()
                    .filter(Objects::nonNull)
                    .toArray(String[]::new);
            if (BinaryUtils.isEmpty(sheetIdArr)) {
                ESResponseStruct struct = new ESResponseStruct();
                struct.setErrorMessage("更新link时需要设置linkKey");
                structList.add(struct);
                return structList;
            }
            ESDiagramSheetQuery sheetQuery = new ESDiagramSheetQuery();
            sheetQuery.setSheetIds(sheetIdArr);
            sheetQuery.setDiagramId(diagramId);
            List<ESDiagramSheetDTO> originSheetList = esDiagramSheetDao.getListByCdt(sheetQuery);

            //对于数据库sheet集合，建立sheetId和logicId之间的映射关系
            Map<String, Long> sheetIdMap = new HashMap<>(16);
            if (!BinaryUtils.isEmpty(originSheetList)) {
                for (ESDiagramSheetDTO originSheet : originSheetList) {
                    sheetIdMap.put(originSheet.getSheetId(), originSheet.getId());
                }
            } else {
                return structList;
            }
            if (BinaryUtils.isEmpty(sheetIdMap)) {
                return structList;
            }
            //根据sheetId获取sheet对象和逻辑id
            List<ESDiagramSheetDTO> skipSheetList = new ArrayList<>();
            for (ESDiagramSheetDTO sheetDTO : saveOrUpdateSheetList) {
                String sheetId = sheetDTO.getSheetId();
                Long sheetLogicId = sheetIdMap.get(sheetId);
                if (!BinaryUtils.isEmpty(sheetLogicId)) {
                    sheetDTO.setId(sheetLogicId);
                } else {
                    //说明已经存在，但是数据库还没处理完，需要跳过处理
                    skipSheetList.add(sheetDTO);
                }
            }
            if (!BinaryUtils.isEmpty(skipSheetList)) {
                saveOrUpdateSheetList.removeAll(skipSheetList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateSheetList)) {
                esDiagramSheetDao.saveOrUpdateBatch(saveOrUpdateSheetList);
            }
        } else {
            //新增操作，需要设置diagramId
            List<ESDiagramSheetDTO> errorSheetList = new ArrayList<>();
            for (ESDiagramSheetDTO saveSheet : saveOrUpdateSheetList) {
                if (StringUtils.isEmpty(saveSheet.getSheetId())) {
                    esResponseStruct.setDiagramId(diagramId);
                    esResponseStruct.setErrorMessage("错误sheet，没有sheetId");
                    structList.add(esResponseStruct);
                    errorSheetList.add(saveSheet);
                    continue;
                }
                saveSheet.setDiagramId(diagramId);
            }
            if (!BinaryUtils.isEmpty(errorSheetList)) {
                saveOrUpdateSheetList.removeAll(errorSheetList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateSheetList)) {
                esDiagramSheetDao.saveOrUpdateBatch(saveOrUpdateSheetList);
            }
        }
        return structList;
    }

    /**
     * @return java.util.List<com.uinnova.project.base.diagram.comm.model.ESResponseStruct>
     * @Author wang
     * @Description 新增或更新node, flag=true标识是更新操作，反之为新增
     * @Date 10:22 2021/8/12
     * @Param [diagramId, sheetId, opList, flag]
     **/
    private List<ESResponseStruct> saveOrUpdateNode(Long diagramId, String sheetId, String opList, Boolean flag) {
        MessageUtil.checkEmpty(diagramId, "保存或更新link时diagramId不能为空");
        MessageUtil.checkEmpty(sheetId, "保存或更新link时sheetId不能为空");
        List<ESDiagramNode> saveOrUpdateNodeList = JSONUtil.toList(opList, ESDiagramNode.class);
        for (ESDiagramNode eachNode : saveOrUpdateNodeList) {
            eachNode.setSheetId(sheetId);
            eachNode.setDiagramId(diagramId);
            eachNode.setCiCode("");
            if (!BinaryUtils.isEmpty(eachNode.getNodeJson())) {
                JSONObject nodeJson = JSONObject.parseObject(eachNode.getNodeJson());
                String ciCode = nodeJson.getString("ciCode");
                if (BinaryUtils.isEmpty(ciCode)) {
                    continue;
                }
                eachNode.setCiCode(ciCode);
            }
        }

        List<ESResponseStruct> structList = new ArrayList<>();
        //更新操作
        if (flag) {
            //获取所有的nodeId，并根据nodeId查出其对应的node对象
            String[] nodeKeyArr = saveOrUpdateNodeList.stream().map(ESDiagramNode::getKey).distinct().toArray(String[]::new);
            if (BinaryUtils.isEmpty(nodeKeyArr)) {
                ESResponseStruct struct = new ESResponseStruct();
                struct.setErrorMessage("更新node时需要设置nodeKey");
                structList.add(struct);
                return structList;
            }
            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
            nodeQuery.setDiagramId(diagramId);
            nodeQuery.setSheetIdEqual(sheetId);
            nodeQuery.setKeys(nodeKeyArr);
            List<ESDiagramNode> originNodeList = esDiagramNodeDao.getListByCdt(nodeQuery);
            //建立nodeId和originId之间的映射关系
            Map<String, Long> nodeIdMap = new HashMap<>();
            if (!BinaryUtils.isEmpty(originNodeList)) {
                for (ESDiagramNode originNode : originNodeList) {
                    nodeIdMap.put(originNode.getKey(), originNode.getId());
                }
            } else {
                return structList;
            }
            if (BinaryUtils.isEmpty(nodeIdMap)) {
                return structList;
            }
            List<ESDiagramNode> skipNodeList = new ArrayList<>();
            for (ESDiagramNode updateNode : saveOrUpdateNodeList) {
                String nodeKey = updateNode.getKey();
                Long tmpLogicId = nodeIdMap.get(nodeKey);
                if (!BinaryUtils.isEmpty(tmpLogicId)) {
                    updateNode.setId(tmpLogicId);
                } else {
                    skipNodeList.add(updateNode);
                }
            }
            if (!BinaryUtils.isEmpty(skipNodeList)) {
                saveOrUpdateNodeList.removeAll(skipNodeList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateNodeList)) {
                esDiagramNodeDao.saveOrUpdateBatch(saveOrUpdateNodeList);
            }
        } else {
            esDiagramNodeDao.saveOrUpdateBatch(saveOrUpdateNodeList);
        }
        return structList;
    }

    /**
     * @return java.util.List<com.uinnova.project.base.diagram.comm.model.ESResponseStruct>
     * @Author wang
     * @Description 新增或更新node, flag=true标识是更新操作，反之为新增
     * @Date 10:22 2021/8/12
     * @Param [diagramId, sheetId, opList, flag]
     **/
    private List<ESResponseStruct> extendSaveOrUpdateNode(Long diagramId, String sheetId, String opList, Boolean flag) {
        MessageUtil.checkEmpty(diagramId, "保存或更新link时diagramId不能为空");
        MessageUtil.checkEmpty(sheetId, "保存或更新link时sheetId不能为空");
        List<ESDiagramNode> saveOrUpdateNodeList = JSONUtil.toList(opList, ESDiagramNode.class);
        for (ESDiagramNode eachNode : saveOrUpdateNodeList) {
            eachNode.setSheetId(sheetId);
            eachNode.setDiagramId(diagramId);
            eachNode.setCiCode("");
            if (!BinaryUtils.isEmpty(eachNode.getNodeJson())) {
                JSONObject nodeJson = JSONObject.parseObject(eachNode.getNodeJson());
                String ciCode = nodeJson.getString("ciCode");
                if (BinaryUtils.isEmpty(ciCode)) {
                    continue;
                }
                eachNode.setCiCode(ciCode);
            }
        }

        List<ESResponseStruct> structList = new ArrayList<>();
        //更新操作
        if (flag) {
            //获取所有的nodeId，并根据nodeId查出其对应的node对象
            String[] nodeKeyArr = saveOrUpdateNodeList.stream().map(ESDiagramNode::getKey).distinct().toArray(String[]::new);
            if (BinaryUtils.isEmpty(nodeKeyArr)) {
                ESResponseStruct struct = new ESResponseStruct();
                struct.setErrorMessage("更新node时需要设置nodeKey");
                structList.add(struct);
                return structList;
            }
            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
            nodeQuery.setDiagramId(diagramId);
            nodeQuery.setSheetIdEqual(sheetId);
            nodeQuery.setKeys(nodeKeyArr);
            List<ESDiagramNode> originNodeList = esDiagramNodeDao.getListByCdt(nodeQuery);
            //建立nodeId和originId之间的映射关系
            Map<String, Long> nodeIdMap = new HashMap<>();
            if (!BinaryUtils.isEmpty(originNodeList)) {
                for (ESDiagramNode originNode : originNodeList) {
                    nodeIdMap.put(originNode.getKey(), originNode.getId());
                }
            } else {
                return structList;
            }
            if (BinaryUtils.isEmpty(nodeIdMap)) {
                return structList;
            }
            List<ESDiagramNode> skipNodeList = new ArrayList<>();
            for (ESDiagramNode updateNode : saveOrUpdateNodeList) {
                String nodeKey = updateNode.getKey();
                Long tmpLogicId = nodeIdMap.get(nodeKey);
                if (!BinaryUtils.isEmpty(tmpLogicId)) {
                    updateNode.setId(tmpLogicId);
                } else {
                    skipNodeList.add(updateNode);
                }
            }
            if (!BinaryUtils.isEmpty(skipNodeList)) {
                saveOrUpdateNodeList.removeAll(skipNodeList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateNodeList)) {
                List<String> nodeKeyList = saveOrUpdateNodeList.stream().map(ESDiagramNode::getKey).collect(Collectors.toList());
                logger.info("修改的node_key为：{}", String.join(",", nodeKeyList));
                esDiagramNodeDao.saveOrUpdateBatch(saveOrUpdateNodeList);
            }
        } else {
            //新增操作，需要设置diagramId和sheetId
            for (ESDiagramNode saveNode : saveOrUpdateNodeList) {
                saveNode.setDiagramId(diagramId);
                saveNode.setSheetId(sheetId);
            }
            List<String> nodeKeyList = saveOrUpdateNodeList.stream().map(ESDiagramNode::getKey).collect(Collectors.toList());
            List<String> distinctNodeKeyList = saveOrUpdateNodeList.stream().map(ESDiagramNode::getKey).distinct().collect(Collectors.toList());
            logger.info("新增的node_key为：{}, 是否重复：{}", String.join(",", nodeKeyList), nodeKeyList.size() == distinctNodeKeyList.size() ? "无" : "有重复");
            ESDiagramNodeQueryBean nodeQuery = new ESDiagramNodeQueryBean();
            nodeQuery.setDiagramId(diagramId);
            nodeQuery.setSheetIdEqual(sheetId);
            nodeQuery.setKeys(distinctNodeKeyList.toArray(new String[0]));
            List<ESDiagramNode> existedNodeList = esDiagramNodeDao.getListByCdt(nodeQuery);
            Map<String, Long> existedNodeMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(existedNodeList)) {
                existedNodeList.forEach(node -> existedNodeMap.put(node.getKey(), node.getId()));
                for (ESDiagramNode node : saveOrUpdateNodeList) {
                    String nodeKey = node.getKey();
                    if (existedNodeMap.containsKey(nodeKey)) {
                        node.setId(existedNodeMap.get(nodeKey));
                    }
                }
                logger.info("新增操作中，修改的node_key为：{}, userId={}, diagramId={}, sheetId={}", String.join(",", existedNodeMap.keySet()), SysUtil.getCurrentUserInfo().getId(), diagramId, sheetId);
            }
            esDiagramNodeDao.saveOrUpdateBatch(saveOrUpdateNodeList);
        }
        return structList;
    }

    /**
     * @return java.util.List<com.uinnova.project.base.diagram.comm.model.ESResponseStruct>
     * @Author wang
     * @Description 新增或更新link, flag为true标识是更新操作
     * @Date 10:22 2021/8/12
     * @Param [diagramId, sheetId, opList, flag]
     **/
    private List<ESResponseStruct> saveOrUpdateLink(Long diagramId, String sheetId, String opList, Boolean flag) {
        MessageUtil.checkEmpty(diagramId, "保存或更新link时diagramId不能为空");
        MessageUtil.checkEmpty(sheetId, "保存或更新link时sheetId不能为空");
        List<ESDiagramLink> saveOrUpdateLinkList = JSONUtil.toList(opList, ESDiagramLink.class);

        for (ESDiagramLink eachLink : saveOrUpdateLinkList) {
            eachLink.setSheetId(sheetId);
            eachLink.setDiagramId(diagramId);
            eachLink.setUniqueCode(null);
            if (!BinaryUtils.isEmpty(eachLink.getLinkJson())) {
                JSONObject linkJson = JSONObject.parseObject(eachLink.getLinkJson());
                String rltCode = linkJson.getString("rltCode");
                if (BinaryUtils.isEmpty(rltCode)) {
                    continue;
                }
                eachLink.setUniqueCode(rltCode);
            }
        }
        List<ESResponseStruct> structList = new ArrayList<>();
        //更新操作
        if (flag) {
            //获取所有的sheetId，并根据sheetId查出其对应的sheet对象
            String[] linkKeyArr = saveOrUpdateLinkList.stream().map(ESDiagramLink::getKey).distinct().toArray(String[]::new);
            if (BinaryUtils.isEmpty(linkKeyArr)) {
                ESResponseStruct struct = new ESResponseStruct();
                struct.setErrorMessage("更新link时需要设置linkKey");
                structList.add(struct);
                return structList;
            }
            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
            linkQuery.setDiagramId(diagramId);
            linkQuery.setSheetIdEqual(sheetId);
            linkQuery.setKeys(linkKeyArr);
            List<ESDiagramLink> originLinkList = esDiagramLinkDao.getListByCdt(linkQuery);
            //建立sheetId和originId之间的映射关系
            Map<String, Long> linkIdMap = new HashMap<>();
            if (!BinaryUtils.isEmpty(originLinkList)) {
                for (ESDiagramLink originLink : originLinkList) {
                    linkIdMap.put(originLink.getKey(), originLink.getId());
                }
            } else {
                return structList;
            }
            if (BinaryUtils.isEmpty(linkIdMap)) {
                return structList;
            }
            List<ESDiagramLink> skipLinkList = new ArrayList<>();
            for (ESDiagramLink updateLink : saveOrUpdateLinkList) {
                String linkKey = updateLink.getKey();
                Long linkLogicId = linkIdMap.get(linkKey);
                if (!BinaryUtils.isEmpty(linkLogicId)) {
                    updateLink.setId(linkLogicId);
                } else {
                    skipLinkList.add(updateLink);
                }
            }
            if (!BinaryUtils.isEmpty(skipLinkList)) {
                saveOrUpdateLinkList.removeAll(skipLinkList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateLinkList)) {
                esDiagramLinkDao.saveOrUpdateBatch(saveOrUpdateLinkList);
            }
            clearLinkUniqueCode(saveOrUpdateLinkList);
        } else {
            //新增操作，需要设置diagramId
            esDiagramLinkDao.saveOrUpdateBatch(saveOrUpdateLinkList);
        }
        return structList;
    }

    /**
     * @return java.util.List<com.uinnova.project.base.diagram.comm.model.ESResponseStruct>
     * @Author wang
     * @Description 新增或更新link, flag为true标识是更新操作
     * @Date 10:22 2021/8/12
     * @Param [diagramId, sheetId, opList, flag]
     **/
    private List<ESResponseStruct> extendSaveOrUpdateLink(Long diagramId, String sheetId, String opList, Boolean flag) {
        MessageUtil.checkEmpty(diagramId, "保存或更新link时diagramId不能为空");
        MessageUtil.checkEmpty(sheetId, "保存或更新link时sheetId不能为空");
        List<ESDiagramLink> saveOrUpdateLinkList = JSONUtil.toList(opList, ESDiagramLink.class);

        for (ESDiagramLink eachLink : saveOrUpdateLinkList) {
            eachLink.setSheetId(sheetId);
            eachLink.setDiagramId(diagramId);
            eachLink.setUniqueCode(null);
            if (!BinaryUtils.isEmpty(eachLink.getLinkJson())) {
                JSONObject linkJson = JSONObject.parseObject(eachLink.getLinkJson());
                String rltCode = linkJson.getString("rltCode");
                if (BinaryUtils.isEmpty(rltCode)) {
                    continue;
                }
                eachLink.setUniqueCode(rltCode);
            }
        }
        List<ESResponseStruct> structList = new ArrayList<>();
        //更新操作
        if (flag) {
            //获取所有的sheetId，并根据sheetId查出其对应的sheet对象
            String[] linkKeyArr = saveOrUpdateLinkList.stream().map(ESDiagramLink::getKey).distinct().toArray(String[]::new);
            if (BinaryUtils.isEmpty(linkKeyArr)) {
                ESResponseStruct struct = new ESResponseStruct();
                struct.setErrorMessage("更新link时需要设置linkKey");
                structList.add(struct);
                return structList;
            }
            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
            linkQuery.setDiagramId(diagramId);
            linkQuery.setSheetIdEqual(sheetId);
            linkQuery.setKeys(linkKeyArr);
            List<ESDiagramLink> originLinkList = esDiagramLinkDao.getListByCdt(linkQuery);
            //建立sheetId和originId之间的映射关系
            Map<String, Long> linkIdMap = new HashMap<>();
            if (!BinaryUtils.isEmpty(originLinkList)) {
                for (ESDiagramLink originLink : originLinkList) {
                    linkIdMap.put(originLink.getKey(), originLink.getId());
                }
            } else {
                return structList;
            }
            if (BinaryUtils.isEmpty(linkIdMap)) {
                return structList;
            }
            List<ESDiagramLink> skipLinkList = new ArrayList<>();
            for (ESDiagramLink updateLink : saveOrUpdateLinkList) {
                String linkKey = updateLink.getKey();
                Long linkLogicId = linkIdMap.get(linkKey);
                if (!BinaryUtils.isEmpty(linkLogicId)) {
                    updateLink.setId(linkLogicId);
                } else {
                    skipLinkList.add(updateLink);
                }
            }
            if (!BinaryUtils.isEmpty(skipLinkList)) {
                saveOrUpdateLinkList.removeAll(skipLinkList);
            }
            if (!BinaryUtils.isEmpty(saveOrUpdateLinkList)) {
                List<String> linkKeyList = saveOrUpdateLinkList.stream().map(ESDiagramLink::getKey).collect(Collectors.toList());
                logger.info("修改的link_key为：{}", String.join(",", linkKeyList));
                esDiagramLinkDao.saveOrUpdateBatch(saveOrUpdateLinkList);
            }
            clearLinkUniqueCode(saveOrUpdateLinkList);
        } else {
            //新增操作，需要设置diagramId
            for (ESDiagramLink saveLink : saveOrUpdateLinkList) {
                saveLink.setDiagramId(diagramId);
                saveLink.setSheetId(sheetId);
            }
            List<String> linkKeyList = saveOrUpdateLinkList.stream().map(ESDiagramLink::getKey).collect(Collectors.toList());
            List<String> distinctLinkKeyList = saveOrUpdateLinkList.stream().map(ESDiagramLink::getKey).distinct().collect(Collectors.toList());
            logger.info("新增的link_key为：{}, 是否重复：{}", String.join(",", linkKeyList), linkKeyList.size() == distinctLinkKeyList.size() ? "无" : "有重复");
            ESDiagramLinkQueryBean linkQuery = new ESDiagramLinkQueryBean();
            linkQuery.setDiagramId(diagramId);
            linkQuery.setSheetIdEqual(sheetId);
            linkQuery.setKeys(distinctLinkKeyList.toArray(new String[0]));
            List<ESDiagramLink> existedLinkList = esDiagramLinkDao.getListByCdt(linkQuery);
            Map<String, Long> existedLinkMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(existedLinkList)) {
                existedLinkList.forEach(link -> existedLinkMap.put(link.getKey(), link.getId()));
                for (ESDiagramLink link : existedLinkList) {
                    String linkKey = link.getKey();
                    if (existedLinkMap.containsKey(linkKey)) {
                        link.setId(existedLinkMap.get(linkKey));
                    }
                }
                logger.info("新增操作中，修改的link_key为：{}, userId={}, diagramId={}, sheetId={}", String.join(",", existedLinkMap.keySet()), SysUtil.getCurrentUserInfo().getId(), diagramId, sheetId);
            }
            esDiagramLinkDao.saveOrUpdateBatch(saveOrUpdateLinkList);
        }
        return structList;
    }

    private void clearLinkUniqueCode(List<ESDiagramLink> linkList) {
        List<Long> linkIds = linkList.stream().filter(e -> BinaryUtils.isEmpty(e.getUniqueCode())).map(ESDiagramLink::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(linkIds)){
            return;
        }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termsQuery("id", linkIds));
        String scriptStr = "ctx._source.uniqueCode=null";
        esDiagramLinkDao.updateByQuery(boolQuery, scriptStr, true);
    }
}
